package com.productivity.view;


import static javax.media.opengl.GL.*;
import static javax.media.opengl.GL2.*;
import static javax.media.opengl.GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT;
import static javax.media.opengl.fixedfunc.GLLightingFunc.GL_SMOOTH;
import static javax.media.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW;
import static javax.media.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION;
import static javax.media.opengl.fixedfunc.GLPointerFunc.GL_VERTEX_ARRAY;

import java.awt.Dimension;
import java.util.List;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;

import com.productivity.control.Scroll;
import com.productivity.model.Game;
import com.productivity.model.GameObject;
import com.productivity.model.common.DrawType;

public class MyCanvas extends GLCanvas implements GLEventListener {
	   private static final int CANVAS_WIDTH = 640;  // width of the drawable
	   private static final int CANVAS_HEIGHT = 480; // height of the drawable
	   public static final int FPS = 60; // animator's target frames per second
	   float[] LightAmbient=		{ 0.1f, 0.1f, 0.1f, 1.0f };
	   float[] LightDiffuse=		{ 0.5f, 0.5f, 0.5f, 1.0f };
	   float[] LightSpecular=		{ 0.7f, 0.7f, 0.7f, 1.0f };
	   float[] Spec=				{ 0.4f, 0.4f, 0.4f, 1.0f };
	   float[] LightPosition=		{ 10.0f, 10.0f, 10.0f, 1.0f };
	   float[] LightDirection=		{ 0.0f, 0.0f, -1.0f, 1.0f };
	 
	   // Setup OpenGL Graphics Renderer
	 
	   private GLU glu;  // for the GL Utility
	   private Game game;
	   /** Constructor to setup the GUI for this Component */
	   public MyCanvas(Scroll control, Game game) {
	      this.addGLEventListener(this);
	      this.addKeyListener(control);
	      this.game = game;
	      setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
	   }
	 
	   // ------ Implement methods declared in GLEventListener ------
	 
	   /**
	    * Called back immediately after the OpenGL context is initialized. Can be used
	    * to perform one-time initialization. Run only once.
	    */
	   @Override
	   public void init(GLAutoDrawable drawable) {
	      GL2 gl = drawable.getGL().getGL2();      // get the OpenGL graphics context
	      glu = new GLU();                         // get GL Utilities
	      gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set background (clear) color
	      gl.glColor3f(0, 0, 0.7f);
	      gl.glClearDepth(1.0f);      // set clear depth value to farthest
	      gl.glEnable(GL_DEPTH_TEST); // enables depth testing
	      gl.glDepthFunc(GL_LEQUAL);  // the type of depth test to do
	      gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // best perspective correction
	      gl.glShadeModel(GL_SMOOTH); // blends colors nicely, and smoothes out lighting
	      gl.glEnable(GL_COLOR_MATERIAL);
	      gl.glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
	      gl.glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Spec, 0);
	      gl.glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50);
	      gl.glEnable(GL_NORMALIZE);
	      gl.glEnable(GL_LIGHTING);
	      gl.glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, LightDirection, 0);
	      gl.glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient,0);		// Setup The Ambient Light
	      gl.glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse,0);		// Setup The Diffuse Light
	      gl.glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular, 0);
	      gl.glLightfv(GL_LIGHT1, GL_POSITION,LightPosition,0);	// Position The Light
	      gl.glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0f);
	      gl.glEnable(GL_LIGHT1);							// Enable Light One
	      // ----- Your OpenGL initialization code here -----
	   }
	 
	   /**
	    * Call-back handler for window re-size event. Also called when the drawable is
	    * first set to visible.
	    */
	   @Override
	   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
	      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
	 
	      if (height == 0) height = 1;   // prevent divide by zero
	      float aspect = (float)width / height;
	 
	      // Set the view port (display area) to cover the entire window
	      gl.glViewport(0, 0, width, height);
	 
	      // Setup perspective projection, with aspect ratio matches viewport
	      gl.glMatrixMode(GL_PROJECTION);  // choose projection matrix
	      gl.glLoadIdentity();             // reset projection matrix
	      glu.gluPerspective(45.0, aspect, 0.1, 100.0); // fovy, aspect, zNear, zFar
	 
	      // Enable the model-view transform
	      gl.glMatrixMode(GL_MODELVIEW);
	      gl.glLoadIdentity(); // reset
	   }
	 
	   /**
	    * Called back by the animator to perform rendering.
	    */
	  
	   @Override
	   public void display(GLAutoDrawable drawable) {
	      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
	      gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers
	      gl.glLoadIdentity();  // reset the model-view matrix
	      
	      game.update();
	      // ----- Your OpenGL rendering code here (Render a white triangle for testing) -----
	      
	      
	      gl.glTranslatef(0, 0, -10);
	      gl.glRotatef(30, 1, 0, 0);
	      
	      gl.glTranslatef(0, 0, game.getCameraLocation().getY()); // translate into the screen
	      gl.glRotatef(game.getCameraLocation().getX(), 0, 1, 0);
	      gl.glLineWidth(2);
	      List<GameObject> lineDrawables = game.getMap().getObjectsofType(DrawType.LINE);
	      for(GameObject ld: lineDrawables) {
		      gl.glPushMatrix();
		      gl.glTranslatef(ld.getLocation().getX()+ld.getDrawOffset().getX(), ld.getLocation().getY()+ld.getDrawOffset().getY(), 0);
		      gl.glScalef(ld.getSize().getX()/ld.getModelSize().getX(), ld.getSize().getY()/ld.getModelSize().getY(), 1);
		      gl.glEnableClientState(GL_VERTEX_ARRAY);
		      gl.glVertexPointer(3, GL_FLOAT, 0, ld.getVertexBuffer());
		      gl.glDrawArrays(GL_LINES, 0, ld.getVertexBuffer().capacity()/3);
		      gl.glPopMatrix();
	      }
	      List<GameObject> tsDrawables = game.getMap().getObjectsofType(DrawType.TRIANGLES);
	      for(GameObject tsd: tsDrawables) {
		      gl.glPushMatrix();
		      gl.glTranslatef(tsd.getLocation().getX()+tsd.getDrawOffset().getX(), tsd.getLocation().getY()+tsd.getDrawOffset().getY(), 0);
		      gl.glScalef(tsd.getSize().getX()/tsd.getModelSize().getX(), tsd.getSize().getY()/tsd.getModelSize().getY(), tsd.getSize().getZ()/tsd.getModelSize().getZ());
		      gl.glEnableClientState(GL_VERTEX_ARRAY);
		      gl.glEnableClientState(GL_NORMAL_ARRAY);
		      gl.glNormalPointer(GL_FLOAT, 0, tsd.getNormalBuffer());
		      gl.glVertexPointer(3, GL_FLOAT, 0, tsd.getVertexBuffer());
		      gl.glDrawArrays(GL.GL_TRIANGLES, 0, tsd.getVertexBuffer().capacity()/3);
		      gl.glPopMatrix();
	      }
	   }
	   
	   /**
	    * Called back before the OpenGL context is destroyed. Release resource such as buffers.
	    */
	   @Override
	   public void dispose(GLAutoDrawable drawable) { }
	
}



